/***************************************************************************
 *   Copyright (C) 2007 by Fernando Pacheco,,,   *
 *   fernando.pacheco@ingesur.com.uy   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include <math.h>

#include "piper.h"

Piper::Piper(double theWidth, double theHeight)
{

  mWidth = theWidth;
  mHeight = theHeight;

  // All margins set -by default- to 3% of the width and height
  mMargin[0] = mWidth*0.03;
  mMargin[1] = mWidth*0.03;
  mMargin[2] = mHeight*0.03;
  mMargin[3] = mHeight*0.03;

  mEMargin[0] = mWidth*0.03;
  mEMargin[1] = mWidth*0.03;
  mEMargin[2] = mHeight*0.03;
  mEMargin[3] = mHeight*0.03;

  mTSepar = mWidth*0.03;

  setTLength();
  setTHeight();
  setVertices();
}

Piper::~Piper()
{

}

void Piper::setTLength()
{
  mTLenght = (mWidth - mMargin[0] - mMargin[1] - mEMargin[0] - mEMargin[1] - mTSepar)/2;
}

void Piper::setTHeight()
{
  mTHeight = sqrt(3/4.0)*mTLenght;
}

void Piper::setLTVertices()
{
  Point myPoint;

  //Left triangle
  //LR
  myPoint.setX(mMargin[0] + mEMargin[0] + mTLenght);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3]);
  mTLVertice.push_back(myPoint);
  //LL
  myPoint.setX(mMargin[0] + mEMargin[0]);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3]);
  mTLVertice.push_back(myPoint);
  //T
  myPoint.setX(mMargin[0] + mEMargin[0] + mTLenght/2);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3] - mTHeight);
  mTLVertice.push_back(myPoint);

/*
  std::cout << "Piper::setLTVertices()" << std::endl;
  for( int cont=0; cont<mTLVertice.size();cont++ ){
    std::cout << "(x,y)=("<< mTLVertice.at(cont).x()<< "," << mTLVertice.at(cont).y()<<")" << std::endl;
  }
*/
}

void Piper::setRTVertices()
{
  Point myPoint;

  //Right triangle
  //LL
  myPoint.setX(mWidth - mMargin[1] - mEMargin[0] - mTLenght);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3]);
  mTRVertice.push_back(myPoint);
  //LR
  myPoint.setX(mWidth - mMargin[1] - mEMargin[1]);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3]);
  mTRVertice.push_back(myPoint);
  //T
  myPoint.setX(mWidth - mMargin[1] - mEMargin[1] - mTLenght/2);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3] - mTHeight);
  mTRVertice.push_back(myPoint);
}

void Piper::setRVertices()
{
  Point myPoint;

  //Rombo
  //L
  myPoint.setX(mMargin[0] + mEMargin[0] + (mTLenght + mTSepar)/2);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3] - sqrt(3/4.0)* (mTLenght + mTSepar));
  mRVertice.push_back(myPoint);
  //R
  myPoint.setX(mMargin[0] + mEMargin[0] + (mTLenght + mTSepar)/2  + mTLenght);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3] - sqrt(3/4.0)* (mTLenght + mTSepar));
  mRVertice.push_back(myPoint);
  //T
  myPoint.setX(mMargin[0] + mEMargin[0] + mTLenght + mTSepar/2);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3] - sqrt(3/4.0)*(2*mTLenght+mTSepar));
  mRVertice.push_back(myPoint);
  //B
  myPoint.setX(mMargin[0] + mEMargin[0] + mTLenght + mTSepar/2);
  myPoint.setY(mHeight - mMargin[3] - mEMargin[3] - sqrt(3/4.0)*mTSepar);
  mRVertice.push_back(myPoint);
}

void Piper::setVertices()
{
  setLTVertices();
  setRTVertices();
  setRVertices();
}

void Piper::setTSepar(double theValue)
{
  if (theValue>0 && theValue<mWidth*0.3)
  {
    mTSepar = theValue;
  } else
  {
    mTSepar = mWidth*0.03;
  }
}

void Piper::setData(VData theData)
{
  mData = theData;
}

VData Piper::data()
{
  return mData;
}

double Piper::width()
{
  return mWidth;
}

double Piper::height()
{
  return mHeight;
}

double Piper::tLenght()
{
  return mTLenght;
}

double Piper::tSepar()
{
  return mTSepar;
}

double Piper::tHeight()
{
  return mTHeight;
}

std::vector<Point> Piper::tLVertice()
{
  return mTLVertice;
}

std::vector<Point> Piper::tRVertice()
{
  return mTRVertice;
}

std::vector<Point> Piper::rVertice()
{
  return mRVertice;
}

Point Piper::lTDataPoint(PData theCData)
{
  Point myPoint;
  double temp;

  temp = mTLVertice.at(0).x() - mTLenght*theCData[0] - mTLenght*theCData[1]/2;
  myPoint.setX(temp);

  temp = mTLVertice.at(0).y() - mTLenght*theCData[1]*sqrt(3/4.0);
  myPoint.setY(temp);

  return myPoint;
}

Point Piper::rTDataPoint(PData theAData)
{
  Point myPoint;
  double temp;

  temp = mTRVertice.at(0).x() + mTLenght*theAData[0] + mTLenght*theAData[1]/2;
  myPoint.setX(temp);

  temp = mTLVertice.at(0).y() - mTLenght*theAData[1]*sqrt(3/4.0);
  myPoint.setY(temp);

  return myPoint;
}

Point Piper::rDataPoint(Point left,Point right)
{
  //By geometry
  Point myPoint;

  double temp1,dY1,l1;
  dY1 = mTLVertice.at(0).y() - left.y() ;
  l1 = dY1/sqrt(3/4.0);
  temp1 = left.x() - l1/2.0;

  double temp2,dY2,l2;
  dY2 = mTRVertice.at(0).y() - right.y() ;
  l2 = dY2/sqrt(3/4.0);
  temp2 = right.x() + l2/2.0;

  myPoint.setX( temp1 + (temp2-temp1)/2.0 );
  myPoint.setY( mTLVertice.at(0).y() - sqrt(3/4.0)*(temp2-temp1) );

  return myPoint;
}

std::vector<PiperPoint> Piper::dataPoint()
{
  std::vector<PiperPoint> myPoints;
  //Iterate in mData and return PiperPoints
  for(int i=0;i < mData.size(); i++)
  {
    PiperPoint myPiperPoint;
    myPiperPoint.id = mData.at(i).id;
    myPiperPoint.name = mData.at(i).name;
    myPiperPoint.lTPoint = lTDataPoint(mData.at(i).cData);
    myPiperPoint.rTPoint = rTDataPoint(mData.at(i).aData);
    myPiperPoint.rPoint = rDataPoint(myPiperPoint.lTPoint, myPiperPoint.rTPoint);
    myPoints.push_back(myPiperPoint);
   }
  return myPoints;
}

std::vector<Line> Piper::lTGrid(double rL,double lT,double tR)
{
  std::vector<Line> myAllLines;

  //lower axis
  for( int cont=1;cont<1/rL;cont++ )
  {
    Point myPIni;
    myPIni.setX( mTLVertice.at(0).x() - mTLenght*cont*rL );
    myPIni.setY( mTLVertice.at(0).y() );
    Point myPEnd;
    myPEnd.setX( mTLVertice.at(1).x() + mTLenght*(1-cont*rL)/2 );
    myPEnd.setY( mTLVertice.at(1).y() - sqrt(3/4.0)*mTLenght*(1-cont*rL) );
    Line myLine=Line(myPIni,myPEnd);
    myAllLines.push_back(myLine);
  }

  //left axis
  for( int cont=1;cont<1/lT;cont++ )
  {
    Point myPIni;
    myPIni.setX( mTLVertice.at(1).x() + mTLenght*cont*lT/2 );
    myPIni.setY( mTLVertice.at(1).y() - sqrt(3/4.0)*mTLenght*cont*lT );
    Point myPEnd;
    myPEnd.setX( mTLVertice.at(0).x() - mTLenght*cont*lT/2 );
    myPEnd.setY( mTLVertice.at(1).y() - sqrt(3/4.0)*mTLenght*cont*lT );
    Line myLine=Line(myPIni,myPEnd);
    myAllLines.push_back(myLine);
  }

  //right axis
  for( int cont=1;cont<1/tR;cont++ )
  {
    Point myPIni;
    myPIni.setX( mTLVertice.at(2).x() + mTLenght*cont*tR/2 );
    myPIni.setY( mTLVertice.at(2).y() + sqrt(3/4.0)*mTLenght*cont*tR );
    Point myPEnd;
    myPEnd.setX( mTLVertice.at(2).x() - mTLenght*(1 -cont*tR)/2 );
    myPEnd.setY( mTLVertice.at(0).y() );
    Line myLine=Line(myPIni,myPEnd);
    myAllLines.push_back(myLine);
  }

  return myAllLines;
}

std::vector<Line> Piper::rTGrid(double lR,double rT,double tL)
{
  std::vector<Line> myAllLines;

  //lower axis
  for( int cont=1;cont<1/lR;cont++ )
  {
    Point myPIni;
    myPIni.setX( mTRVertice.at(0).x() + mTLenght*cont*lR );
    myPIni.setY( mTRVertice.at(0).y() );
    Point myPEnd;
    myPEnd.setX( mTRVertice.at(0).x() - mTLenght*cont*lR/2 );
    myPEnd.setY( mTRVertice.at(0).y() - sqrt(3/4.0)*mTLenght*(1-cont*lR) );
    Line myLine=Line(myPIni,myPEnd);
    myAllLines.push_back(myLine);
  }

  //right axis
  for( int cont=1;cont<1/rT;cont++ )
  {
    Point myPIni;
    myPIni.setX( mTRVertice.at(1).x() + mTLenght*cont*rT/2 );
    myPIni.setY( mTRVertice.at(1).y() - sqrt(3/4.0)*mTLenght*cont*rT );
    Point myPEnd;
    myPEnd.setX( mTRVertice.at(1).x() + mTLenght*(1 -cont*rT) );
    myPEnd.setY( mTRVertice.at(1).y() - sqrt(3/4.0)*mTLenght*cont*rT );
    Line myLine=Line(myPIni,myPEnd);
    myAllLines.push_back(myLine);
  }

  //left axis
  for( int cont=1;cont<1/tL;cont++ )
  {
    Point myPIni;
    myPIni.setX( mTRVertice.at(2).x() + mTLenght*cont*tL/2 );
    myPIni.setY( mTRVertice.at(2).y() + sqrt(3/4.0)*mTLenght*cont*tL );
    Point myPEnd;
    myPEnd.setX( mTRVertice.at(2).x() - mTLenght*(1 -cont*tL)/2 );
    myPEnd.setY( mTRVertice.at(0).y() );
    Line myLine=Line(myPIni,myPEnd);
    myAllLines.push_back(myLine);
  }

  return myAllLines;
}

std::vector<Line> Piper::rGrid(double l,double r)
{
  std::vector<Line> myAllLines;
  ///@todo Do it!!!.
  return myAllLines;
}
